package core;

import static org.lwjgl.opengl.GL11.*;

import java.awt.Canvas;

import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;

public abstract class Game {
   private int fps;
   protected SpriteBatch spriteBatch;
   boolean running = false;
  
   public Game(boolean vsync) {
      try {
         Display.setFullscreen(true);
         Display.setVSyncEnabled(vsync);
      } catch(Exception exc) {
         exc.printStackTrace();
      }
   }

   public Game(String name, int width, int height, boolean resizable) {
      Display.setTitle(name);

      try {
         Display.setDisplayMode(new DisplayMode(width, height));
      } catch(Exception exc) {
         exc.printStackTrace();
      }

      Display.setResizable(resizable);

      fps = 60;
   }

   public void setFPS(int fps) {
      this.fps = fps;
   }

   public int getFPS() {
      return fps;
   }

   public final void run() {
      run(false);
   }

   public final void run(boolean core) {
      run(core, new PixelFormat());
   }

   public final void run(boolean core, PixelFormat format) {
      run(format, core ? new ContextAttribs(3, 3).withProfileCore(true) : null);
   }

   public final void run(int major, int minor) {
      run(major, minor, false);
   }

   public final void run(int major, int minor, boolean core) {
      run(major, minor, core, new PixelFormat());
   }

   public final void run(int major, int minor, boolean core, PixelFormat format) {
      run(format, core ? new ContextAttribs(major, minor).withProfileCore(core) : new ContextAttribs(major, minor));
   }

   public final void run(PixelFormat format) {
      run(format, null);
   }

   public final void run(ContextAttribs attribs) {
      run(new PixelFormat(), attribs);
   }

   public void setRenderTarget(Canvas canvas) throws LWJGLException{
      Display.setParent(canvas);
      
   }
   
   public final void run(PixelFormat format, ContextAttribs attribs) {
      try {
         //System.setProperty("org.lwjgl.opengl.Window.undecorated", "true");
//         System.setProperty("org.lwjgl.opengl.Display.allowSoftwareOpenGL", "true");
//         System.setProperty("org.lwjgl.util.Debug", "true");
         Display.create(format, attribs);
         glEnable(GL_BLEND);
         glEnable(GL_DEPTH_TEST);
         glColorMask(true,true,true,true);
         glClearColor(0.4f, 0.6f, 0.93f, 0f);
         spriteBatch = new SpriteBatch(100);
         running = true;
      } catch(Exception exc) {
         exc.printStackTrace();
         System.exit(1);
      }
      gameLoop();
   }

   private void gameLoop() {
      init();
      resized();

      
      long lastTime, lastFPS;
      lastTime = lastFPS = System.nanoTime();
      int frames = 0;
      
      while(!Display.isCloseRequested() && !shouldStop()) {
         long deltaTime = System.nanoTime() - lastTime;
         lastTime += deltaTime;
         
         if(Display.wasResized())
            resized();
         
         update(deltaTime);
         
         render();
         
         Display.update();
         
         frames++;
         if(System.nanoTime() - lastFPS >= 1e9) {
            Display.setTitle(("FPS: ".concat(String.valueOf(frames))));
            lastFPS += 1e9;
            frames = 0;
         }
         
         Display.sync(fps);
      }
   }

   public int getWidth() {
      return Display.getWidth();
   }

   public int getHeight() {
      return Display.getHeight();
   }

   public abstract void init();

   public void resized() {
      glViewport(0, 0, getWidth(), getHeight());
      spriteBatch.recalculateViewport();
   }

   public boolean shouldStop() {
      return Keyboard.isKeyDown(Keyboard.KEY_ESCAPE);
   }

   public void keyPressed(int key, char c) {}

   public void keyReleased(int key, char cs) {}

   public void update(long deltaTime) {}

   public void render(){
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   }

   public void destroy() {
      Display.destroy();
      System.exit(0);
   }
}